package cn.cew.bytespyserver.vm;

import cn.cew.bytespyserver.tool.BaseUtils;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author chenenwei
 * @version 1.0.0
 * @description TODO
 * @createTime 2022-10-13 11:29:00
 */
@Slf4j
public class VmAttach {

    /**
     * attach 并 load 代理程序
     * @param jvmPid 母包程序进程pid
     * @param agentFilePath 代理程序jar绝对路径，如： c:/xxx/spy.jar
     * @param args 代理参数
     * @throws IOException
     */
    public static void attach (String jvmPid, String agentFilePath, String args) throws IOException {

        VirtualMachine jvm = null;
        try {

            log.info("Attaching to target JVM with PID: {}", jvmPid);
            jvm = VirtualMachine.attach(jvmPid);
            jvm.loadAgent(agentFilePath, args);
            log.info("Attached to target JVM and loaded Java agent successfully");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            assert jvm != null;
            jvm.detach();
        }
    }

    /**
     * 获取java 虚拟机列表
     * @param name 虚拟机名称
     * @return
     */
    public static List<VmDescriptor> listVirtualMachine (String name) {

        List<VmDescriptor> vmDescriptors = new ArrayList<>();
        List<VirtualMachineDescriptor> list = VirtualMachine.list();
        if (BaseUtils.isEmpty(list)) {
            return null;
        }
        List<VirtualMachineDescriptor> targetList = null;
        if (BaseUtils.isNotEmpty(name)) {
            targetList = list.stream().filter(v -> v.displayName().contains(name)).collect(Collectors.toList());
            if (BaseUtils.isEmpty(targetList)) {
                return null;
            }
        } else {
            targetList = list;
        }
        for (VirtualMachineDescriptor vm : targetList) {
            vmDescriptors.add(new VmDescriptor(vm.id(), vm.displayName()));
        }
        return vmDescriptors;
    }
}
